package prgechecsimpl_a;

import java.util.*;
import prgechecsmodel.IBoard;
import prgechecsmodel.IMove;

final class HistoryData {

    MoveA m;
    int capture;
    int castle;
    int ep;
    int fifty;
}

final public class BoardA implements IBoard {

    public long zobristKey;
    final static int LIGHT = 0;
    final static int DARK = 1;
    final static int PAWN = 0;
    final static int KNIGHT = 1;
    final static int BISHOP = 2;
    final static int ROOK = 3;
    final static int QUEEN = 4;
    final static int KING = 5;
    final static int EMPTY = 6;
    final static char A1 = 56;
    final static char B1 = 57;
    final static char C1 = 58;
    final static char D1 = 59;
    final static char E1 = 60;
    final static char F1 = 61;
    final static char G1 = 62;
    final static char H1 = 63;
    final static char A8 = 0;
    final static char B8 = 1;
    final static char C8 = 2;
    final static char D8 = 3;
    final static char E8 = 4;
    final static char F8 = 5;
    final static char G8 = 6;
    final static char H8 = 7;
    final static int DOUBLED_PAWN_PENALTY = 10;
    final static int ISOLATED_PAWN_PENALTY = 20;
    final static int BACKWARDS_PAWN_PENALTY = 8;
    final static int PASSED_PAWN_BONUS = 20;
    final static int ROOK_SEMI_OPEN_FILE_BONUS = 10;
    final static int ROOK_OPEN_FILE_BONUS = 15;
    final static int ROOK_ON_SEVENTH_BONUS = 20;
    final static int HIST_STACK = 400;
    int side = LIGHT;
    int xside = DARK;
    int castle = 15;
    int ep = -1;
    int fifty = 0;
    int hply = 0;
    int history[][] = new int[ 64 ][ 64 ];
    HistoryData histDat[] = new HistoryData[ HIST_STACK ];
    int pawnRank[][] = new int[ 2 ][ 10 ];
    int pieceMat[] = new int[ 2 ];
    int pawnMat[] = new int[ 2 ];
    int color[] = {
        1, 1, 1, 1, 1, 1, 1, 1,
        1, 1, 1, 1, 1, 1, 1, 1,
        6, 6, 6, 6, 6, 6, 6, 6,
        6, 6, 6, 6, 6, 6, 6, 6,
        6, 6, 6, 6, 6, 6, 6, 6,
        6, 6, 6, 6, 6, 6, 6, 6,
        0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0
    };
    int piece[] = {
        3, 1, 2, 4, 5, 2, 1, 3,
        0, 0, 0, 0, 0, 0, 0, 0,
        6, 6, 6, 6, 6, 6, 6, 6,
        6, 6, 6, 6, 6, 6, 6, 6,
        6, 6, 6, 6, 6, 6, 6, 6,
        6, 6, 6, 6, 6, 6, 6, 6,
        0, 0, 0, 0, 0, 0, 0, 0,
        3, 1, 2, 4, 5, 2, 1, 3
    };
    final char pieceChar[] = {'P', 'N', 'B', 'R', 'Q', 'K'};
    private boolean slide[] = {false, false, true, true, true, false};
    private int offsets[] = {0, 8, 4, 4, 8, 8};
    private int offset[][] = {
        {0, 0, 0, 0, 0, 0, 0, 0},
        {-21, -19, -12, -8, 8, 12, 19, 21},
        {-11, -9, 9, 11, 0, 0, 0, 0},
        {-10, -1, 1, 10, 0, 0, 0, 0},
        {-11, -10, -9, -1, 1, 9, 10, 11},
        {-11, -10, -9, -1, 1, 9, 10, 11}
    };
    int mailbox[] = {
        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
        -1, 0, 1, 2, 3, 4, 5, 6, 7, -1,
        -1, 8, 9, 10, 11, 12, 13, 14, 15, -1,
        -1, 16, 17, 18, 19, 20, 21, 22, 23, -1,
        -1, 24, 25, 26, 27, 28, 29, 30, 31, -1,
        -1, 32, 33, 34, 35, 36, 37, 38, 39, -1,
        -1, 40, 41, 42, 43, 44, 45, 46, 47, -1,
        -1, 48, 49, 50, 51, 52, 53, 54, 55, -1,
        -1, 56, 57, 58, 59, 60, 61, 62, 63, -1,
        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
    };
    int mailbox64[] = {
        21, 22, 23, 24, 25, 26, 27, 28,
        31, 32, 33, 34, 35, 36, 37, 38,
        41, 42, 43, 44, 45, 46, 47, 48,
        51, 52, 53, 54, 55, 56, 57, 58,
        61, 62, 63, 64, 65, 66, 67, 68,
        71, 72, 73, 74, 75, 76, 77, 78,
        81, 82, 83, 84, 85, 86, 87, 88,
        91, 92, 93, 94, 95, 96, 97, 98
    };
    int castleMask[] = {
        7, 15, 15, 15, 3, 15, 15, 11,
        15, 15, 15, 15, 15, 15, 15, 15,
        15, 15, 15, 15, 15, 15, 15, 15,
        15, 15, 15, 15, 15, 15, 15, 15,
        15, 15, 15, 15, 15, 15, 15, 15,
        15, 15, 15, 15, 15, 15, 15, 15,
        15, 15, 15, 15, 15, 15, 15, 15,
        13, 15, 15, 15, 12, 15, 15, 14
    };
    /* the values of the pieces */
    int pieceValue[] = {
        100, 300, 300, 500, 900, 0
    };
    /* The "pcsq" arrays are piece/square tables. They're values
    added to the material value of the piece based on the
    location of the piece. */
    int pawnPcsq[] = {
        0, 0, 0, 0, 0, 0, 0, 0,
        5, 10, 15, 20, 20, 15, 10, 5,
        4, 8, 12, 16, 16, 12, 8, 4,
        3, 6, 9, 12, 12, 9, 6, 3,
        2, 4, 6, 8, 8, 6, 4, 2,
        1, 2, 3, -10, -10, 3, 2, 1,
        0, 0, 0, -40, -40, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0
    };
    int knightPcsq[] = {
        -10, -10, -10, -10, -10, -10, -10, -10,
        -10, 0, 0, 0, 0, 0, 0, -10,
        -10, 0, 5, 5, 5, 5, 0, -10,
        -10, 0, 5, 10, 10, 5, 0, -10,
        -10, 0, 5, 10, 10, 5, 0, -10,
        -10, 0, 5, 5, 5, 5, 0, -10,
        -10, 0, 0, 0, 0, 0, 0, -10,
        -10, -30, -10, -10, -10, -10, -30, -10
    };
    int bishopPcsq[] = {
        -10, -10, -10, -10, -10, -10, -10, -10,
        -10, 0, 0, 0, 0, 0, 0, -10,
        -10, 0, 5, 5, 5, 5, 0, -10,
        -10, 0, 5, 10, 10, 5, 0, -10,
        -10, 0, 5, 10, 10, 5, 0, -10,
        -10, 0, 5, 5, 5, 5, 0, -10,
        -10, 0, 0, 0, 0, 0, 0, -10,
        -10, -10, -20, -10, -10, -20, -10, -10
    };
    int kingPcsq[] = {
        -40, -40, -40, -40, -40, -40, -40, -40,
        -40, -40, -40, -40, -40, -40, -40, -40,
        -40, -40, -40, -40, -40, -40, -40, -40,
        -40, -40, -40, -40, -40, -40, -40, -40,
        -40, -40, -40, -40, -40, -40, -40, -40,
        -40, -40, -40, -40, -40, -40, -40, -40,
        -20, -20, -20, -20, -20, -20, -20, -20,
        0, 20, 40, -20, 0, -20, 40, 20
    };
    int kingEndgamePcsq[] = {
        0, 10, 20, 30, 30, 20, 10, 0,
        10, 20, 30, 40, 40, 30, 20, 10,
        20, 30, 40, 50, 50, 40, 30, 20,
        30, 40, 50, 60, 60, 50, 40, 30,
        30, 40, 50, 60, 60, 50, 40, 30,
        20, 30, 40, 50, 50, 40, 30, 20,
        10, 20, 30, 40, 40, 30, 20, 10,
        0, 10, 20, 30, 30, 20, 10, 0
    };
    /* The flip array is used to calculate the piece/square
    values for DARK pieces. The piece/square value of a
    LIGHT pawn is pawnPcsq[sq] and the value of a DARK
    pawn is pawnPcsq[flip[sq]] */
    int flip[] = {
        56, 57, 58, 59, 60, 61, 62, 63,
        48, 49, 50, 51, 52, 53, 54, 55,
        40, 41, 42, 43, 44, 45, 46, 47,
        32, 33, 34, 35, 36, 37, 38, 39,
        24, 25, 26, 27, 28, 29, 30, 31,
        16, 17, 18, 19, 20, 21, 22, 23,
        8, 9, 10, 11, 12, 13, 14, 15,
        0, 1, 2, 3, 4, 5, 6, 7
    };

    @Override
    public int getColor(int i, int j) {
        return color[(i << 3) + j];
    }

    @Override
    public int getPiece(int i, int j) {
        return piece[(i << 3) + j];
    }

    @Override
    public boolean isWhiteToMove() {
        return (side == LIGHT);
    }

    /* inCheck() returns true if side s is in check and false
    otherwise. It just scans the board to find side s's king
    and calls attack() to see if it's being attacked. */
    @Override
    public boolean inCheck(int s) {
        int i;

        for (i = 0 ; i < 64 ; ++i) {
            if (piece[i] == KING && color[i] == s) {
                return attack(i, s ^ 1);
            }
        }
        return true;  /* shouldn't get here */
    }


    /* attack() returns true if square sq is being attacked by side
    s and false otherwise. */
    boolean attack(int sq, int s) {
        int i, j, n;

        for (i = 0 ; i < 64 ; ++i) {
            if (color[i] == s) {
                int p = piece[i];
                if (p == PAWN) {
                    if (s == LIGHT) {
                        if (COL(i) != 0 && i - 9 == sq) {
                            return true;
                        }
                        if (COL(i) != 7 && i - 7 == sq) {
                            return true;
                        }
                    } else {
                        if (COL(i) != 0 && i + 7 == sq) {
                            return true;
                        }
                        if (COL(i) != 7 && i + 9 == sq) {
                            return true;
                        }
                    }
                } else {
                    for (j = 0 ; j < offsets[p] ; ++j) {
                        for (n = i ;;) {
                            n = mailbox[mailbox64[n] + offset[p][j]];
                            if (n == -1) {
                                break;
                            }
                            if (n == sq) {
                                return true;
                            }
                            if (color[n] != EMPTY) {
                                break;
                            }
                            if (!slide[p]) {
                                break;
                            }
                        }
                    }
                }
            }
        }
        return false;
    }


    /* gen() generates pseudo-legal moves for the current position.
    It scans the board to find friendly pieces and then determines
    what squares they attack. When it finds a piece/square
    combination, it calls genPush to put the move on the "move
    stack." */
    @Override
    public TreeSet<IMove> gen() {
        TreeSet<IMove> ret = new TreeSet<IMove>();

        for (int i = 0 ; i < 64 ; ++i) {
            if (color[i] == side) {
                if (piece[i] == PAWN) {
                    if (side == LIGHT) {
                        if (COL(i) != 0 && color[i - 9] == DARK) {
                            genPush(ret, i, i - 9, 17);
                        }
                        if (COL(i) != 7 && color[i - 7] == DARK) {
                            genPush(ret, i, i - 7, 17);
                        }
                        if (color[i - 8] == EMPTY) {
                            genPush(ret, i, i - 8, 16);
                            if (i >= 48 && color[i - 16] == EMPTY) {
                                genPush(ret, i, i - 16, 24);
                            }
                        }
                    } else {
                        if (COL(i) != 0 && color[i + 7] == LIGHT) {
                            genPush(ret, i, i + 7, 17);
                        }
                        if (COL(i) != 7 && color[i + 9] == LIGHT) {
                            genPush(ret, i, i + 9, 17);
                        }
                        if (color[i + 8] == EMPTY) {
                            genPush(ret, i, i + 8, 16);
                            if (i <= 15 && color[i + 16] == EMPTY) {
                                genPush(ret, i, i + 16, 24);
                            }
                        }
                    }
                } else {
                    for (int j = 0 ; j < offsets[piece[i]] ; ++j) {
                        for (int n = i ;;) {
                            n = mailbox[mailbox64[n] + offset[piece[i]][j]];
                            if (n == -1) {
                                break;
                            }
                            if (color[n] != EMPTY) {
                                if (color[n] == xside) {
                                    genPush(ret, i, n, 1);
                                }
                                break;
                            }
                            genPush(ret, i, n, 0);
                            if (!slide[piece[i]]) {
                                break;
                            }
                        }
                    }
                }
            }
        }

        /* generate castle moves */
        if (side == LIGHT) {
            if ((castle & 1) != 0) {
                genPush(ret, E1, G1, 2);
            }
            if ((castle & 2) != 0) {
                genPush(ret, E1, C1, 2);
            }
        } else {
            if ((castle & 4) != 0) {
                genPush(ret, E8, G8, 2);
            }
            if ((castle & 8) != 0) {
                genPush(ret, E8, C8, 2);
            }
        }

        /* generate en passant moves */
        if (ep != -1) {
            if (side == LIGHT) {
                if (COL(ep) != 0 && color[ep + 7] == LIGHT && piece[ep + 7] == PAWN) {
                    genPush(ret, ep + 7, ep, 21);
                }
                if (COL(ep) != 7 && color[ep + 9] == LIGHT && piece[ep + 9] == PAWN) {
                    genPush(ret, ep + 9, ep, 21);
                }
            } else {
                if (COL(ep) != 0 && color[ep - 9] == DARK && piece[ep - 9] == PAWN) {
                    genPush(ret, ep - 9, ep, 21);
                }
                if (COL(ep) != 7 && color[ep - 7] == DARK && piece[ep - 7] == PAWN) {
                    genPush(ret, ep - 7, ep, 21);
                }
            }
        }
        return ret;
    }


    /* genCaps() is basically a copy of gen() that's modified to
    only generate capture and promote moves. It's used by the
    quiescence search. */
    @Override
    public TreeSet<IMove> genCaps() {
        TreeSet<IMove> ret = new TreeSet<IMove>();

        for (int i = 0 ; i < 64 ; ++i) {
            if (color[i] == side) {
                if (piece[i] == PAWN) {
                    if (side == LIGHT) {
                        if (COL(i) != 0 && color[i - 9] == DARK) {
                            genPush(ret, i, i - 9, 17);
                        }
                        if (COL(i) != 7 && color[i - 7] == DARK) {
                            genPush(ret, i, i - 7, 17);
                        }
                        if (i <= 15 && color[i - 8] == EMPTY) {
                            genPush(ret, i, i - 8, 16);
                        }
                    }
                    if (side == DARK) {
                        if (COL(i) != 0 && color[i + 7] == LIGHT) {
                            genPush(ret, i, i + 7, 17);
                        }
                        if (COL(i) != 7 && color[i + 9] == LIGHT) {
                            genPush(ret, i, i + 9, 17);
                        }
                        if (i >= 48 && color[i + 8] == EMPTY) {
                            genPush(ret, i, i + 8, 16);
                        }
                    }
                } else {
                    for (int j = 0 ; j < offsets[piece[i]] ; ++j) {
                        for (int n = i ;;) {
                            n = mailbox[mailbox64[n] + offset[piece[i]][j]];
                            if (n == -1) {
                                break;
                            }
                            if (color[n] != EMPTY) {
                                if (color[n] == xside) {
                                    genPush(ret, i, n, 1);
                                }
                                break;
                            }
                            if (!slide[piece[i]]) {
                                break;
                            }
                        }
                    }
                }
            }
        }
        if (ep != -1) {
            if (side == LIGHT) {
                if (COL(ep) != 0 && color[ep + 7] == LIGHT && piece[ep + 7] == PAWN) {
                    genPush(ret, ep + 7, ep, 21);
                }
                if (COL(ep) != 7 && color[ep + 9] == LIGHT && piece[ep + 9] == PAWN) {
                    genPush(ret, ep + 9, ep, 21);
                }
            } else {
                if (COL(ep) != 0 && color[ep - 9] == DARK && piece[ep - 9] == PAWN) {
                    genPush(ret, ep - 9, ep, 21);
                }
                if (COL(ep) != 7 && color[ep - 7] == DARK && piece[ep - 7] == PAWN) {
                    genPush(ret, ep - 7, ep, 21);
                }
            }
        }
        return ret;
    }

    /* genPush() puts a move on the move stack, unless it's a
    pawn promotion that needs to be handled by genPromote().
    It also assigns a score to the move for alpha-beta move
    ordering. If the move is a capture, it uses MVV/LVA
    (Most Valuable Victim/Least Valuable Attacker). Otherwise,
    it uses the move's history heuristic value. Note that
    1,000,000 is added to a capture move's score, so it
    always gets ordered above a "normal" move. */
    @Override
    public void genPush(TreeSet<IMove> ret, int from, int to, int bits) {
        if ((bits & 16) != 0) {
            if (side == LIGHT) {
                if (to <= H8) {
                    genPromote(ret, from, to, bits);
                    return;
                }
            } else {
                if (to >= A1) {
                    genPromote(ret, from, to, bits);
                    return;
                }
            }
        }

        IMove g = new MoveA(from, to, 0, bits);

//        if (color[to] != EMPTY) {
//            g.setScore(1000000 + (piece[to] * 10) - piece[from]);
//        } else {
//            g.setScore(history[from][to]);
//        }
        ret.add(g);
    }


    /* genPromote() is just like genPush(), only it puts 4 moves
    on the move stack, one for each possible promotion piece */
    @Override
    public void genPromote(TreeSet<IMove> ret, int from, int to, int bits) {
        for (char i = KNIGHT ; i <= QUEEN ; ++i) {
            MoveA g = new MoveA(from, to, i, (bits | 32));
            g.setScore(1000000 + (i * 10));
            ret.add(g);
        }
    }

    /* makemove() makes a move. If the move is illegal, it
    undoes whatever it did and returns false. Otherwise, it
    returns true. */
    boolean makeMove(MoveA m) {

        /* test to see if a castle move is legal and move the rook
        (the king is moved with the usual move code later) */
        if ((m.bits & 2) != 0) {
            int from, to;

            if (inCheck(side)) {
                return false;
            }
            switch (m.to) {
                case 62:
                    if (color[F1] != EMPTY || color[G1] != EMPTY ||
                            attack(F1, xside) || attack(G1, xside)) {
                        return false;
                    }
                    from = H1;
                    to = F1;
                    break;
                case 58:
                    if (color[B1] != EMPTY || color[C1] != EMPTY || color[D1] != EMPTY ||
                            attack(C1, xside) || attack(D1, xside)) {
                        return false;
                    }
                    from = A1;
                    to = D1;
                    break;
                case 6:
                    if (color[F8] != EMPTY || color[G8] != EMPTY ||
                            attack(F8, xside) || attack(G8, xside)) {
                        return false;
                    }
                    from = H8;
                    to = F8;
                    break;
                case 2:
                    if (color[B8] != EMPTY || color[C8] != EMPTY || color[D8] != EMPTY ||
                            attack(C8, xside) || attack(D8, xside)) {
                        return false;
                    }
                    from = A8;
                    to = D8;
                    break;
                default:  /* shouldn't get here */
                    from = -1;
                    to = -1;
                    break;
            }
            color[to] = color[from];
            piece[to] = piece[from];
            color[from] = EMPTY;
            piece[from] = EMPTY;
        }

        /* back up information so we can take the move back later. */
        histDat[hply] = new HistoryData();
        histDat[hply].m = m;
        histDat[hply].capture = piece[m.to];
        histDat[hply].castle = castle;
        histDat[hply].ep = ep;
        histDat[hply].fifty = fifty;
        ++hply;

        /* update the castle, en passant, and
        fifty-move-draw variables */
        castle &= castleMask[m.from] & castleMask[m.to];
        if ((m.bits & 8) != 0) {
            if (side == LIGHT) {
                ep = m.to + 8;
            } else {
                ep = m.to - 8;
            }
        } else {
            ep = -1;
        }
        if ((m.bits & 17) != 0) {
            fifty = 0;
        } else {
            ++fifty;
        }

        /* move the piece */
        color[m.to] = side;
        if ((m.bits & 32) != 0) {
            piece[m.to] = m.promote;
        } else {
            piece[m.to] = piece[m.from];
        }
        color[m.from] = EMPTY;
        piece[m.from] = EMPTY;

        /* erase the pawn if this is an en passant move */
        if ((m.bits & 4) != 0) {
            if (side == LIGHT) {
                color[m.to + 8] = EMPTY;
                piece[m.to + 8] = EMPTY;
            } else {
                color[m.to - 8] = EMPTY;
                piece[m.to - 8] = EMPTY;
            }
        }

        /* switch sides and test for legality (if we can capture
        the other guy's king, it's an illegal position and
        we need to take the move back) */
        side ^= 1;
        xside ^= 1;
        if (inCheck(xside)) {
            takeBack();
            return false;
        }
        return true;
    }


    /* takeBack() is very similar to makeMove(), only backwards :)  */
    @Override
    public void takeBack() {
        side ^= 1;
        xside ^= 1;
        --hply;
        MoveA m = histDat[hply].m;
        castle = histDat[hply].castle;
        ep = histDat[hply].ep;
        fifty = histDat[hply].fifty;
        color[m.from] = side;
        if ((m.bits & 32) != 0) {
            piece[m.from] = PAWN;
        } else {
            piece[m.from] = piece[m.to];
        }
        if (histDat[hply].capture == EMPTY) {
            color[m.to] = EMPTY;
            piece[m.to] = EMPTY;
        } else {
            color[m.to] = xside;
            piece[m.to] = histDat[hply].capture;
        }
        if ((m.bits & 2) != 0) {
            int from, to;

            switch (m.to) {
                case 62:
                    from = F1;
                    to = H1;
                    break;
                case 58:
                    from = D1;
                    to = A1;
                    break;
                case 6:
                    from = F8;
                    to = H8;
                    break;
                case 2:
                    from = D8;
                    to = A8;
                    break;
                default:  /* shouldn't get here */
                    from = -1;
                    to = -1;
                    break;
            }
            color[to] = side;
            piece[to] = ROOK;
            color[from] = EMPTY;
            piece[from] = EMPTY;
        }
        if ((m.bits & 4) != 0) {
            if (side == LIGHT) {
                color[m.to + 8] = xside;
                piece[m.to + 8] = PAWN;
            } else {
                color[m.to - 8] = xside;
                piece[m.to - 8] = PAWN;
            }
        }
    }

    @Override
    public String toString() {
        int i;

        StringBuffer sb = new StringBuffer("\n8 ");
        for (i = 0 ; i < 64 ; ++i) {
            switch (color[i]) {
                case EMPTY:
                    sb.append(" .");
                    break;
                case LIGHT:
                    sb.append(" ");
                    sb.append(pieceChar[piece[i]]);
                    break;
                case DARK:
                    sb.append(" ");
                    sb.append((char) (pieceChar[piece[i]] + ('a' - 'A')));
                    break;
                default:
                    throw new IllegalStateException("Square not EMPTY, LIGHT or DARK: " + i);
            }
            if ((i + 1) % 8 == 0 && i != 63) {
                sb.append("\n");
                sb.append(Integer.toString(7 - ROW(i)));
                sb.append(" ");
            }
        }
        sb.append("\n\n   a b c d e f g h\n\n");
        return sb.toString();
    }

    /* reps() returns the number of times that the current
    position has been repeated. Thanks to John Stanback
    for this clever algorithm. */
    @Override
    public int reps() {
        int b[] = new int[ 64 ];
        int c = 0;  /* count of squares that are different from
        the current position */
        int r = 0;  /* number of repetitions */

        /* is a repetition impossible? */
        if (fifty <= 3) {
            return 0;
        }

        /* loop through the reversible moves */
        for (int i = hply - 1 ; i >= hply - fifty - 1 ; --i) {
            if (++b[histDat[i].m.from] == 0) {
                --c;
            } else {
                ++c;
            }
            if (--b[histDat[i].m.to] == 0) {
                --c;
            } else {
                ++c;
            }
            if (c == 0) {
                ++r;
            }
        }

        return r;
    }

    static int COL(int x) {
        return (x & 7);
    }

    static int ROW(int x) {
        return (x >> 3);
    }

    @Override
    public int distance(int squareA, int squareB) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public int gen_allLegalMoves(TreeSet<IMove> moves, int startIndex) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public int gen_allLegalMoves(int[] moves, int i) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public boolean validate(int move) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public boolean isAttacked(int attacked, int side) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public boolean makeMove(IMove m) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public void makeMove(int i) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public int rank(int index) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public int col(int x) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public void setupStart() {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public void unmakeMove(int move) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public String getFen() {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public void inputFen(String fen) {
        throw new UnsupportedOperationException("Not supported yet.");
    }
}
